#pragma once

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <strings.h>
#include <cstring>
#include <unistd.h>
#include <wait.h>
#include <pthread.h>
#include <functional>

#include "log.hpp"
#include "Inet_Addr.hpp"
#include "threadpool.hpp"

using server_task_t = std::function<void()>;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    RECV_ERROR,
    SEND_ERROR
};

const static int g_backlog = 16;
const static int listen_default_sockfd = -1;
static ThreadPool<server_task_t> tp(3);

class tcpServer
{
private:
    struct threadData
    {
        threadData(int sockfd, InetAddr addr, tcpServer* self)
        : _sockfd(sockfd), _addr(addr), _self(self)
        {}

        int _sockfd;
        InetAddr _addr;
        tcpServer* _self;
    };
public:
    tcpServer(uint16_t port)
        : _listen_sockfd(listen_default_sockfd), _port(port)
    {
        tp.threadInit();
        tp.threadStart();
    }

    void serverInit()
    {
        LOG(DEBUG, "serverInit begin.......");

        // 创建套接字
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sockfd < 0)
        {
            LOG(FATA, "socket() error");
            exit(SO_ERROR);
        }

        // 绑定bind
        struct sockaddr_in serverAddr;
        bzero(&serverAddr, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = _port;
        serverAddr.sin_addr.s_addr = INADDR_ANY;

        int ret = bind(_listen_sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
        if (ret < 0)
        {
            LOG(FATA, "bind() error");
            exit(BIND_ERROR);
        }

        // 监听，等待连接
        ret = listen(_listen_sockfd, g_backlog);
        if (ret < 0)
        {
            LOG(FATA, "listen() error");
            exit(LISTEN_ERROR);
        }

        LOG(INFO, "serverInit success!!!");
    }

    static void* serverHandler(void* arg)
    {
        pthread_detach(pthread_self());
        threadData* data = (threadData*)arg;
        data->_self->server(data->_sockfd, data->_addr);

        delete data;
        return nullptr;
    }

    void server(int sockfd, InetAddr clientAddr)
    {
        LOG(INFO, "[%s:%d] link success", clientAddr.IP().c_str(), clientAddr.Port());

        while (true)
        {
            char clientMassage[1024]{0};
            // 收消息
            int rn = recv(sockfd, clientMassage, sizeof(clientMassage) - 1, 0);
            if (rn > 0)
            {
                LOG(INFO, "server recv: %s", clientMassage);
                // 发消息echo
                int sn = send(sockfd, clientMassage, strlen(clientMassage), 0);
                if (sn < 0)
                {
                    LOG(ERROR, "send() error");
                    break;  
                }

            }
            if (rn == 0)
            {
                // 客户端退出&&连接中断
                LOG(WORING, "[%s:%d] quit.....", clientAddr.IP().c_str(), clientAddr.Port());
                break;
            }
            if (rn < 0)
            {
                LOG(ERROR, "recv() error");
                break;
            }
        }

        close(sockfd);
    }

    void serverLoop()
    {
        LOG(DEBUG, "serverLoop begin.....");

        while (true)
        {
            // 记录请求连接方（client）的socket信息
            struct sockaddr_in clientAddr;
            bzero(&clientAddr, sizeof(clientAddr));
            socklen_t cAddrLen = sizeof(clientAddr);

            // 接收连接
            int sockfd = accept(_listen_sockfd, (struct sockaddr *)&clientAddr, &cAddrLen);
            if (sockfd < 0)
            {
                LOG(ERROR, "accept failed");
                continue;
            }

            // 连接成功，开始通信

            //v0，只允许一个请求
            //server(sockfd, InetAddr(clientAddr));

            //v1 多进程
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     //child
            //     close(_listen_sockfd);

            //     pid_t id = fork();
            //     if (id > 0) exit(0);
            //     if (id == 0)    //子进程退出后，孙子进程直接被1号进程领养
            //     {
            //         server(sockfd, InetAddr(clientAddr));
            //         exit(0);
            //     }
            //     // if (fork() > 0)
            //     //     exit(0);
            //     // server(sockfd, InetAddr(clientAddr));
            //     // exit(0);
            // }

            // //father
            // close(sockfd);   //必须关闭，否则会造成文件描述符泄露
            // waitpid(pid, nullptr, 0);

            //v2多线程
            //server_task_t t = std::bind(&tcpServer::serverHandler, this, sockfd, clientAddr, std::placeholders::_1);
            // pthread_t tid;
            // threadData *data = new threadData(sockfd, InetAddr(clientAddr), this);
            // int ret = pthread_create(&tid, nullptr, serverHandler, data);
            
            //v3线程池
            server_task_t t = std::bind(&tcpServer::server, this, sockfd, clientAddr);
            tp.enQueue(t);
            
        }
    }

    ~tcpServer()
    {
        tp.threadWait();
    }

private:
    int _listen_sockfd;
    uint16_t _port;
};